/*
 * @lc app=leetcode.cn id=312 lang=java
 *
 * [312] 戳气球
 *
 * https://leetcode-cn.com/problems/burst-balloons/description/
 *
 * algorithms
 * Hard (56.60%)
 * Likes:    166
 * Dislikes: 0
 * Total Accepted:    5.9K
 * Total Submissions: 10.5K
 * Testcase Example:  '[3,1,5,8]'
 *
 * 有 n 个气球，编号为0 到 n-1，每个气球上都标有一个数字，这些数字存在数组 nums 中。
 *
 * 现在要求你戳破所有的气球。每当你戳破一个气球 i 时，你可以获得 nums[left] * nums[i] * nums[right] 个硬币。 这里的
 * left 和 right 代表和 i 相邻的两个气球的序号。注意当你戳破了气球 i 后，气球 left 和气球 right 就变成了相邻的气球。
 *
 * 求所能获得硬币的最大数量。
 *
 * 说明:
 *
 *
 * 你可以假设 nums[-1] = nums[n] = 1，但注意它们不是真实存在的所以并不能被戳破。
 * 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
 *
 *
 * 示例:
 *
 * 输入: [3,1,5,8]
 * 输出: 167
 * 解释: nums = [3,1,5,8] --> [3,5,8] -->   [3,8]   -->  [8]  --> []
 * coins =  3*1*5      +  3*5*8    +  1*3*8      + 1*8*1   = 167
 *
 *
 */

// @lc code=start
class Solution {
    int[][] dp;
    int[] nums;

    public int maxCoins(int[] nums) {
        this.nums = nums;
        int length = nums.length;
        this.dp = new int[nums.length][nums.length];
        /**
         *
         *
         * for(int i=0; i<length; i++)
            dp[i][i] = nums[i];
         */

        return dfs(0, length-1);
    }

    int dfs(int left, int right) {

        if(left > right) {
            return 0;
        }

        if(dp[left][right] != 0) {
            return dp[left][right];
        }
        int coins = 0;
        for(int i=left; i <= right; i++) {
            coins = Math.max(coins, dfs(left, i-1) + getNum(left-1)*getNum(i)*getNum(right+1) + dfs(i+1, right));
        }
        dp[left][right] = coins;

        return coins;
    }

    int getNum(int index) {
        if(index < 0 || index >= this.nums.length) {
            return 1;
        }
        return this.nums[index];
    }
}
// @lc code=end

